local Obj = require("core.Obj")
local ObjMonster = require("core.ObjMonster")
local ObjHuman = require("core.ObjHuman")
local Msg = require("core.Msg")
local Timer = require("core.Timer")
local Util = require("common.Util")
local Buffer = require("buffer.Buffer")
local Skill = require("skill.Skill")
local Conditions = require("skill.Conditions")
local Notify = require("skill.Notify")
local SkillDefine = require("skill.Define")
local RoleDefine = require("role.RoleDefine")
local Utilitys = require("skill.Utilitys")
local BufferExcel = require("excel.Buffer").Buff
local BufferCmdExcel = require("excel.Buffer").BuffCmd
local BufferNotify = require("buffer.Notify")
local SkillExcel = require("excel.Skill").Skill
local SceneEvent = require("core.SceneEvent")
local CombatCalc = require("skill.CombatCalc")
local SkillCallback = require("skill.Callback")

local SkillCoolDown	= require("skill.CoolDown")
local HorseLogic = require("horse.HorseLogic")
local Status = require("scene.Status")
local baseAttrInitValue = require("excel.Role").baseAttrInitValue[1]

passive = {}	--被动
loopCall = {}	--定时调用
rateCalcs = {}	--比例特殊计算
calcs = {}		--最后计算

setTypeArgs = {}--特殊类型处理 例如连线
other = {}		--其他特殊情况
adds = {}		--添加BUF时调用
remove = {}		--移出BUF时调用

local adds2key		= {}
local loopCall2key  = {}
local random		= math.random


function onRemove(obj,buf)
	local id = buf.id
	local bufAttr = obj.bufAttr
	if bufAttr.baojiCallSkill then 
		bufAttr.baojiCallSkill[id] = nil
	end
	if bufAttr.shanbiCallSkill then 
		bufAttr.shanbiCallSkill[id] = nil
	end
	if bufAttr.gedangCallSkill then 
		bufAttr.gedangCallSkill[id] = nil
	end
	if bufAttr.beHitCallSkill then 
		bufAttr.beHitCallSkill[id] = nil
	end
	if bufAttr.hitCallSkill then 
		bufAttr.hitCallSkill[id] = nil
	end
--[[	
	for _,key in ipairs(adds2key) do
		if buf[key] then
			buf[key] = nil
		end
	end
	
	for _,key in ipairs(loopCall2key) do
		if buf[key] then
			buf[key] = nil
		end
	end
	
--]]	
	local config = BufferExcel[buf.id]
	local call = _ENV.remove[config.cmd]
	if call then
		call(obj,buf)
	end
end

function onAdd(obj,buf,config)
	local cmd = config.cmd
	local callback = adds[cmd]
	if callback then
		local cmdConfig = BufferCmdExcel[cmd]
		callback(obj,buf,config,cmdConfig,Buffer.getAppendArg(buf,config,cmdConfig))
	end
end

function addHp(obj, hp, senderID)
	local currHp = Obj.getHp(obj)
	if currHp<1 or hp==0 then return end	-- 目标死亡
	if hp>0 then
		hp = passive.hpRate(obj, hp)
		Obj.setHp(obj, currHp+hp)
		Notify.GC_SKILL_HIT(obj, senderID, -hp)
	else
		local sender = Obj.objs[senderID]
		if hp > -1 then
		    hp = -1
		end
		SkillCallback.onAttack(sender, obj, nil, nil, true, nil, nil, -hp)
	end
end

-- ****************  命令列表  ******************
function baojiUp(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.BAOJI_UP] = bufAttr[RoleDefine.BAOJI_UP] or 0
	bufAttr[RoleDefine.BAOJI_UP] = bufAttr[RoleDefine.BAOJI_UP] + value
end

function calcs.baojiUp(attr,bufAttr)
	if not attr[RoleDefine.BAOJI_UP] then return end
	attr[RoleDefine.BAOJI_UP] = attr[RoleDefine.BAOJI_UP] + bufAttr[RoleDefine.BAOJI_UP]
end

function baojiDown(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.BAOJI_DOWN] = bufAttr[RoleDefine.BAOJI_DOWN] or 0
	bufAttr[RoleDefine.BAOJI_DOWN] = bufAttr[RoleDefine.BAOJI_DOWN] + value
end

function calcs.baojiDown(attr,bufAttr)
	attr[RoleDefine.BAOJI_DOWN] = attr[RoleDefine.BAOJI_DOWN] + bufAttr[RoleDefine.BAOJI_DOWN]
end

function speed(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr

	bufAttr.speedRateAdd = bufAttr.speedRateAdd or 0
	bufAttr.speedRateDec = bufAttr.speedRateDec or 0
	
	if value >=0 then	--加速
		bufAttr.speedRateAdd = math.max(value,bufAttr.speedRateAdd)
	else				--减速
		bufAttr.speedRateDec = math.min(value,bufAttr.speedRateDec)
	end
	
	bufAttr[RoleDefine.SPEED_RATE] = bufAttr.speedRateAdd + bufAttr.speedRateDec

end

function rateCalcs.speed(attr,bufAttr)
	attr[RoleDefine.SPEED_RATE] = (attr[RoleDefine.SPEED_RATE] or 0) + bufAttr[RoleDefine.SPEED_RATE]
end

function hitRate(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr.hitRate = bufAttr.hitRate or 0
	bufAttr.hitRate = bufAttr.hitRate + value
end

function passive.hitRate(obj)
	local bufAttr = obj.bufAttr
	bufAttr.hitRate = bufAttr.hitRate or 0
	return bufAttr.hitRate
end

function shanbiRate(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr.shanbiRate = bufAttr.shanbiRate or 0
	bufAttr.shanbiRate = bufAttr.shanbiRate + value
end

function passive.shanbiRate(obj)
	local bufAttr = obj.bufAttr
	if not bufAttr then
		assert(nil, obj.obj_type)
	end
	bufAttr.shanbiRate = bufAttr.shanbiRate or 0
	return bufAttr.shanbiRate
end

function baojiRate(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr.baojiRate = bufAttr.baojiRate or 0
	bufAttr.baojiRate = bufAttr.baojiRate + value
end

function passive.baojiRate(obj)
	local bufAttr = obj.bufAttr
	bufAttr.baojiRate = bufAttr.baojiRate or 0
	return bufAttr.baojiRate
end


function renxingRate(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr.renxingRate = bufAttr.renxingRate or 0
	bufAttr.renxingRate = bufAttr.renxingRate + value
end

function passive.renxingRate(obj)
	local bufAttr = obj.bufAttr
	bufAttr.renxingRate = bufAttr.renxingRate or 0
	return bufAttr.renxingRate
end

function hit(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.HIT] = bufAttr[RoleDefine.HIT] or 0
	bufAttr[RoleDefine.HIT] = bufAttr[RoleDefine.HIT] + value
end

function calcs.hit(attr,bufAttr)
	attr[RoleDefine.HIT] = attr[RoleDefine.HIT]+bufAttr[RoleDefine.HIT]
end

function shanbi(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.SHANBI] = bufAttr[RoleDefine.SHANBI] or 0
	bufAttr[RoleDefine.SHANBI] = bufAttr[RoleDefine.SHANBI] + value
end

function calcs.shanbi(attr,bufAttr)
	if not attr[RoleDefine.SHANBI] then return end
	attr[RoleDefine.SHANBI] = attr[RoleDefine.SHANBI]+bufAttr[RoleDefine.SHANBI]
end

function baoji(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.BAOJI] = bufAttr[RoleDefine.BAOJI] or 0
	bufAttr[RoleDefine.BAOJI] = bufAttr[RoleDefine.BAOJI] + value
end

function calcs.baoji(attr,bufAttr)
	if not attr[RoleDefine.BAOJI] then return end
	attr[RoleDefine.BAOJI] = attr[RoleDefine.BAOJI]+bufAttr[RoleDefine.BAOJI]
end

function renxing(obj,buf,config,cmdConfig,value)
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.RENXING] = bufAttr[RoleDefine.RENXING] or 0
	bufAttr[RoleDefine.RENXING] = bufAttr[RoleDefine.RENXING] + value
end

function calcs.renxing(attr,bufAttr)
	attr[RoleDefine.RENXING] = attr[RoleDefine.RENXING]+bufAttr[RoleDefine.RENXING]
end

function atk(obj,buf,config,cmdConfig,rate,value)	--攻击增加、减少
	assert(value,buf.id)
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.ATK] = bufAttr[RoleDefine.ATK] or 0
	bufAttr[RoleDefine.ATK] = bufAttr[RoleDefine.ATK] + value
	bufAttr.atkRate = bufAttr.atkRate or 0
	bufAttr.atkRate = bufAttr.atkRate + rate
end

function calcs.atk(attr,bufAttr)
	attr[RoleDefine.ATK] = attr[RoleDefine.ATK]+bufAttr[RoleDefine.ATK]
end

function rateCalcs.atk(attr,bufAttr)
	attr[RoleDefine.ATK_RATE] = (attr[RoleDefine.ATK_RATE] or 0)+bufAttr.atkRate
end 


function def(obj,buf,config,cmdConfig,rate,value)
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.DEF] = bufAttr[RoleDefine.DEF] or 0
	bufAttr[RoleDefine.DEF] = bufAttr[RoleDefine.DEF] + value
	bufAttr.defRate = bufAttr.defRate or 0
	bufAttr.defRate = bufAttr.defRate + rate
end

function calcs.def(attr,bufAttr)
	attr[RoleDefine.DEF] = attr[RoleDefine.DEF] or 0
	attr[RoleDefine.DEF] = math.max(attr[RoleDefine.DEF]+bufAttr[RoleDefine.DEF],0)
end
function rateCalcs.def(attr,bufAttr)
	attr[RoleDefine.DEF_RATE] = (attr[RoleDefine.DEF_RATE] or 0)+bufAttr.defRate
end 

--眩晕值
function xuanyun(obj, buf,config, cmdConfig, value)
   local bufAttr= obj.bufAttr
   bufAttr[RoleDefine.GIDDY] = bufAttr[RoleDefine.GIDDY] or 0
   bufAttr[RoleDefine.GIDDY] = bufAttr[RoleDefine.GIDDY]  + value
end
function calcs.xuanyun(attr,bufAttr)
   attr[RoleDefine.GIDDY] = attr[RoleDefine.GIDDY] or 0
   attr[RoleDefine.GIDDY] = math.max(attr[RoleDefine.GIDDY] + bufAttr[RoleDefine.GIDDY], 0)
end
--眩晕机率
function xuanyunRate(obj, buf,config, cmdConfig, value)
  local bufAttr = obj.bufAttr
  bufAttr.xuanyunRate = bufAttr.xuanyunRate or 0
  bufAttr.xuanyunRate = bufAttr.xuanyunRate + value
end
function passive.xuanyunRate(obj)
  local bufAttr = obj.bufAttr
  if not bufAttr then
    assert(nil, obj.obj_type)
  end
  bufAttr.xuanyunRate = bufAttr.xuanyunRate or 0
  return bufAttr.xuanyunRate
end
--抗晕值
function kangyun(obj, buf,config, cmdConfig, value)
   local bufAttr= obj.bufAttr
   bufAttr[RoleDefine.GIDDY_KX] = bufAttr[RoleDefine.GIDDY_KX] or 0
   bufAttr[RoleDefine.GIDDY_KX] = bufAttr[RoleDefine.GIDDY_KX]  + value
end
function calcs.kangyun(attr,bufAttr)
   attr[RoleDefine.GIDDY_KX] = attr[RoleDefine.GIDDY_KX] or 0
   attr[RoleDefine.GIDDY_KX] = math.max(attr[RoleDefine.GIDDY_KX] + bufAttr[RoleDefine.GIDDY_KX], 0)
end
--抗晕几率
function kangyunRate(obj, buf,config, cmdConfig, value)
  local bufAttr = obj.bufAttr
  bufAttr.kangyunRate = bufAttr.kangyunRate or 0
  bufAttr.kangyunRate = bufAttr.kangyunRate + value
end
function passive.kangyunRate(obj)
  local bufAttr = obj.bufAttr
  if not bufAttr then
    assert(nil, obj.obj_type)
  end
  bufAttr.kangyunRate = bufAttr.kangyunRate or 0
  return bufAttr.kangyunRate
end
--骑术值
function qishu(obj, buf,config, cmdConfig, value)
   local bufAttr= obj.bufAttr
   bufAttr[RoleDefine.QISHU] = bufAttr[RoleDefine.QISHU] or 0
   bufAttr[RoleDefine.QISHU] = bufAttr[RoleDefine.QISHU]  + value
end
function calcs.qishu(attr,bufAttr)
   attr[RoleDefine.QISHU] = attr[RoleDefine.QISHU] or 0
   attr[RoleDefine.QISHU] = math.max(attr[RoleDefine.QISHU] + bufAttr[RoleDefine.QISHU], 0)
end
--抗落马率
function qishuRate(obj, buf,config, cmdConfig, value)
  local bufAttr = obj.bufAttr
  bufAttr.qishuRate = bufAttr.qishuRate or 0
  bufAttr.qishuRate = bufAttr.qishuRate + value
end
function passive.qishuRate(obj)
  local bufAttr = obj.bufAttr
  if not bufAttr then
    assert(nil, obj.obj_type)
  end
  bufAttr.qishuRate = bufAttr.qishuRate or 0
  return bufAttr.qishuRate
end
--落马值
function luomazhi(obj, buf,config, cmdConfig, value)
   local bufAttr= obj.bufAttr
   bufAttr[RoleDefine.LUOMA] = bufAttr[RoleDefine.LUOMA] or 0
   bufAttr[RoleDefine.LUOMA] = bufAttr[RoleDefine.LUOMA]  + value
end
function calcs.luomazhi(attr,bufAttr)
   attr[RoleDefine.LUOMA] = attr[RoleDefine.LUOMA] or 0
   attr[RoleDefine.LUOMA] = math.max(attr[RoleDefine.LUOMA] + bufAttr[RoleDefine.LUOMA], 0)
end
--落马率
function luomaRate(obj, buf,config, cmdConfig, value)
  local bufAttr = obj.bufAttr
  bufAttr.luomaRate = bufAttr.luomaRate or 0
  bufAttr.luomaRate = bufAttr.luomaRate + value
end
function passive.luomaRate(obj)
  local bufAttr = obj.bufAttr
  if not bufAttr then
    assert(nil, obj.obj_type)
  end
  bufAttr.luomaRate = bufAttr.luomaRate or 0
  return bufAttr.luomaRate
end

--怪物免伤
function monsterAvoid(obj, buf,config, cmdConfig, value)
   local bufAttr= obj.bufAttr
   bufAttr[RoleDefine.MONSTER_KX] = bufAttr[RoleDefine.MONSTER_KX] or 0
   bufAttr[RoleDefine.MONSTER_KX] = bufAttr[RoleDefine.MONSTER_KX]  + value
end
function calcs.monsterAvoid(attr,bufAttr)
   attr[RoleDefine.MONSTER_KX] = attr[RoleDefine.MONSTER_KX] or 0
   attr[RoleDefine.MONSTER_KX] = math.max(attr[RoleDefine.MONSTER_KX] + bufAttr[RoleDefine.MONSTER_KX], 0)
end
 
 --猛将免伤
function mengjiangAvoid(obj, buf,config, cmdConfig, value)
   local bufAttr= obj.bufAttr
   bufAttr[RoleDefine.MENGJIANG_KX] = bufAttr[RoleDefine.MENGJIANG_KX] or 0
   bufAttr[RoleDefine.MENGJIANG_KX] = bufAttr[RoleDefine.MENGJIANG_KX]  + value
end
function calcs.mengjiangAvoid(attr,bufAttr)
   attr[RoleDefine.MENGJIANG_KX] = attr[RoleDefine.MENGJIANG_KX] or 0
   attr[RoleDefine.MENGJIANG_KX] = math.max(attr[RoleDefine.MENGJIANG_KX] + bufAttr[RoleDefine.MENGJIANG_KX], 0)
end

--神谋免伤
function shenmouAvoid(obj, buf,config, cmdConfig, value)
   local bufAttr= obj.bufAttr
   bufAttr[RoleDefine.SHENMOU_KX] = bufAttr[RoleDefine.SHENMOU_KX] or 0
   bufAttr[RoleDefine.SHENMOU_KX] = bufAttr[RoleDefine.SHENMOU_KX]  + value
end
function calcs.shenmouAvoid(attr,bufAttr)
   attr[RoleDefine.SHENMOU_KX] = attr[RoleDefine.SHENMOU_KX] or 0
   attr[RoleDefine.SHENMOU_KX] = math.max(attr[RoleDefine.SHENMOU_KX] + bufAttr[RoleDefine.SHENMOU_KX], 0)
end
--讯影免伤
function xunyingAvoid(obj, buf,config, cmdConfig, value)
   local bufAttr= obj.bufAttr
   bufAttr[RoleDefine.XUNYING_KX] = bufAttr[RoleDefine.XUNYING_KX] or 0
   bufAttr[RoleDefine.XUNYING_KX] = bufAttr[RoleDefine.XUNYING_KX]  + value
end
function calcs.xunyingAvoid(attr,bufAttr)
   attr[RoleDefine.XUNYING_KX] = attr[RoleDefine.XUNYING_KX] or 0
   attr[RoleDefine.XUNYING_KX] = math.max(attr[RoleDefine.XUNYING_KX] + bufAttr[RoleDefine.XUNYING_KX], 0)
end

function makeShanghai(obj,buf,config,cmdConfig,rate,value)	--造成伤害增加、减少
	local bufAttr = obj.bufAttr
	bufAttr.makeShanghai = bufAttr.makeShanghai or 0
	bufAttr.makeShanghaiRate = bufAttr.makeShanghaiRate or 0
	
	bufAttr.makeShanghai = bufAttr.makeShanghai + value
	bufAttr.makeShanghaiRate = bufAttr.makeShanghaiRate + rate
end

function passive.makeShanghai(send,recv)
	local sendBufAttr = send.bufAttr
	local recvBufAttr = recv.bufAttr
	
	local makeShanghaiMonster,makeShanghaiRateMonster = passive.makeShanghaiMonster(send,recv)
	local makeShanghai = (sendBufAttr.makeShanghai or 0) + makeShanghaiMonster
	local makeShanghaiRate = (sendBufAttr.makeShanghaiRate or 0) + makeShanghaiRateMonster + (Utilitys.getAttrMount(send,RoleDefine.MAKE_SHANGHAI_RATE) or 0)
	
	local recvShanghai = (recvBufAttr.recvShanghai or 0)*-1
	local recvShanghaiRate = (recvBufAttr.recvShanghaiRate or 0)*-1 + (recv.attr and recv.attr[RoleDefine.RECV_SHANGHAI_RATE] or 0)
	
	return makeShanghaiMonster,makeShanghaiRateMonster,makeShanghai,makeShanghaiRate,recvShanghai,recvShanghaiRate
--	return CombatCalc.getMakeShanghai(shangHai,shangHaiJiaShen,shangHaiJianMian,kangXingJianShang,makeShanghaiRate,recvShanghaiRate,makeShanghai,recvShanghai)
end

if not typeStrs then
	typeStrs	 = {}
	typeRateStrs = {}
	for i=0,1000 do
		typeStrs[i]  = "makeShanghaiMonster" .. i
		typeRateStrs[i]  = "makeShanghaiRateMonster" .. i
	end
end

function makeShanghaiMonster(obj,buf,config,cmdConfig,rate,value,type)	--对怪物造成伤害增加、减少
	local bufAttr = obj.bufAttr
	
	local makeShanghaiMonsterType =	typeStrs[type]
	local makeShanghaiRateMonsterType = typeRateStrs[type]
	
	
	bufAttr[makeShanghaiMonsterType] = bufAttr[makeShanghaiMonsterType] or 0
	bufAttr[makeShanghaiRateMonsterType] = bufAttr[makeShanghaiRateMonsterType] or 0
	
	bufAttr[makeShanghaiMonsterType] = bufAttr[makeShanghaiMonsterType] + value
	bufAttr[makeShanghaiRateMonsterType] = bufAttr[makeShanghaiRateMonsterType] + rate
	
	bufAttr.makeShanghaiMonster = true
end

function passive.makeShanghaiMonster(send,recv)	--对怪物造成伤害增加、减少
	if recv.obj_type ~= Obj.TYPE_MONSTER then
		return 0,0
	end
	
	local type = ObjMonster.getValue(recv, "monster_type")
	local makeShanghaiMonsterType = typeStrs[type]
	local makeShanghaiRateMonsterType = typeRateStrs[type]
	
	return send.bufAttr[makeShanghaiMonsterType] or 0, send.bufAttr[makeShanghaiRateMonsterType] or 0
end
 
function recvShanghai(obj,buf,config,cmdConfig,rate,value)
	assert(value,buf.id)
	local bufAttr = obj.bufAttr
	bufAttr.recvShanghai = bufAttr.recvShanghai or 0
	bufAttr.recvShanghaiRate = bufAttr.recvShanghaiRate or 0
	bufAttr.recvShanghai = bufAttr.recvShanghai + value
	bufAttr.recvShanghaiRate = bufAttr.recvShanghaiRate + rate
end

function adds.maxHP(obj,buf,config,cmdConfig,rate,value, isRecover)
	if not isRecover then return end
	
	maxHP(obj,buf,config,cmdConfig,rate,value)
	calcs.maxHP(obj.attr,obj.bufAttr)
	rateCalcs.maxHP(obj.attr,obj.bufAttr)
	
	addHp(obj,obj.attr[RoleDefine.HP_MAX]*rate+value,obj.id)
	ObjHuman.sendAttr(obj, RoleDefine.HP_MAX)
end

function maxHP(obj,buf,config,cmdConfig,rate,value)
	local bufAttr = obj.bufAttr
	bufAttr.maxHP = bufAttr.maxHP or 0
	bufAttr.maxHPRate = bufAttr.maxHPRate or 0
	
	bufAttr.maxHP = bufAttr.maxHP + value
	bufAttr.maxHPRate = bufAttr.maxHPRate + rate
end

function calcs.maxHP(attr,bufAttr)
	attr[RoleDefine.HP_MAX] = attr[RoleDefine.HP_MAX]+bufAttr.maxHP
end

function rateCalcs.maxHP(attr,bufAttr)
  attr[RoleDefine.HP_MAX_RATE] = (attr[RoleDefine.HP_MAX_RATE] or 0) +bufAttr.maxHPRate
end

function adds.fixMaxHP(obj,buf,config,cmdConfig,value) 
  if obj.obj_type ~= Obj.TYPE_HUMAN then
      assert()
  end 
  fixMaxHP(obj,buf,config,cmdConfig,value)
  calcs.fixMaxHP(obj.attr,obj.bufAttr)  
  ObjHuman.sendAttr(obj, RoleDefine.HP_MAX)
  ObjHuman.setHp(obj, obj.bufAttr.fixMaxHP)
end

function fixMaxHP(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr.fixMaxHP = bufAttr.fixMaxHP or 0  
  bufAttr.fixMaxHP = bufAttr.fixMaxHP + value
end
function calcs.fixMaxHP(attr,bufAttr)
  attr[RoleDefine.HP_MAX] = bufAttr.fixMaxHP
end



function maxMP(obj,buf,config,cmdConfig,rate,value)
	local bufAttr = obj.bufAttr
	
	bufAttr.maxMP = bufAttr.maxMP or 0
	bufAttr.maxMPRate = bufAttr.maxMPRate or 0
	
	bufAttr.maxMP = bufAttr.maxMP + value
	bufAttr.maxMPRate = bufAttr.maxMPRate + rate
end

function calcs.maxMP(attr,bufAttr)
	if attr[RoleDefine.MP_MAX] then
		attr[RoleDefine.MP_MAX] = attr[RoleDefine.MP_MAX]*(1+bufAttr.maxMPRate) + bufAttr.maxMP
	end
end


function adds.hpShanghai(obj,buf,config,cmdConfig,rate,value,hpRate,mianAttr,mainAttrRate)
	local mustHit = true
	local send	= Buffer.getSender(buf)
	if not send.attr then	-- AOE
		send = Obj.getOwner(send)
		if not send then return end
	end
	local isHit,isHeavyHit,isGedang,shanghai,noBaoJiShanghai = CombatCalc.hurt(send,obj,1,0,0,0,mianAttr,mainAttrRate,mustHit)
	shanghai = (noBaoJiShanghai or 0)*rate+value

	buf.param = math.floor(shanghai +  Obj.getHpMax(obj)*hpRate)
end


function loopCall.hpShanghai(obj,buf)
	local send = Buffer.getSender(buf)

	if not send or buf.param == nil or buf.param <= 0 then return end
	--[[
	if passive.invincible(obj) or passive.tempInvincible(obj) then  -- 无敌 -- 临时无敌
		local mm = Msg.gc.GC_SKILL_TIP
		mm.type = 3
		mm.obj_id = obj.id
		Msg.send(mm,obj.fd)
		Msg.send(mm,send.fd)
		return
	end	]]	
	
	--local hp = Obj.getHp(obj)	
	--local hpShanghai = passive.shanghaiOffset(send,obj,buf.hpShanghai)	-- 伤害抵消
	local shangHai = buf.param
	shangHai = shangHai * random((1-baseAttrInitValue.hurt_rate)*100,(1+baseAttrInitValue.hurt_rate)*100)*0.01 
	if shangHai < 5 then
      shangHai = random(1,5)
  end  
	addHp(obj,-shangHai,buf.sendID)
end

function adds.hpRecover(obj,buf,config,cmdConfig,rate,value,hpRate,mianAttr)
	local attr = obj.attr
	local hp = attr[RoleDefine.ATK]*rate + value +  Obj.getHpMax(obj)*hpRate + (mianAttr and mianAttr~=0 and attr[mianAttr] or 0)
	buf.param = hp
end

function loopCall.hpRecover(obj,buf)
	addHp(obj,buf.param,obj.id)
end

function adds.mp(obj,buf,config,cmdConfig,value)
	buf.param = value
end



function loopCall.mp(obj,buf)
	if obj.obj_type ~= Obj.TYPE_HUMAN then return end
	ObjHuman.setMp(obj, obj.db.mp + buf.param)
	ObjHuman.sendAreaHpMp(obj)
end

function defCt(obj,buf,config,cmdConfig,rate,value)
	local bufAttr = obj.bufAttr
	
	bufAttr.defCtRate = bufAttr.defCtRate or 0 
	bufAttr.defCt = bufAttr.defCt or 0
	
	bufAttr.defCtRate = bufAttr.defCtRate + rate
	bufAttr.defCt = bufAttr.defCt + value
	
end

function passive.defCt(send,def,hujia_ct,dikang_ct)
	local bufAttr = send.bufAttr
	bufAttr.defCtRate = bufAttr.defCtRate or 0 
	bufAttr.defCt = bufAttr.defCt or 0
	return CombatCalc.getDefCt(def,hujia_ct,dikang_ct,bufAttr.defCtRate,bufAttr.defCt)
end


function hpRate(obj,buf,config,cmdConfig,rate)	--治疗效果增加、减少
	local bufAttr = obj.bufAttr
	
	bufAttr.hpRate = bufAttr.hpRate or 0 
	bufAttr.hpRate = bufAttr.hpRate + rate
end

function calcs.hpRate(attr,bufAttr)
	if attr[RoleDefine.HP_RATE] then
		attr[RoleDefine.HP_RATE] = math.max(attr[RoleDefine.HP_RATE] + bufAttr.hpRate,0)
	end
end

function passive.hpRate(obj,hp)
	return hp*(obj.attr[RoleDefine.HP_RATE] or 0)
end

function gedangRate(obj,buf,config,cmdConfig,rate)	
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.GEDANG_RATE] = bufAttr[RoleDefine.GEDANG_RATE] or 0
	bufAttr[RoleDefine.GEDANG_RATE] = bufAttr[RoleDefine.GEDANG_RATE] + rate
end

function calcs.gedangRate(attr,bufAttr)
	if not attr[RoleDefine.GEDANG_RATE] then return end
	attr[RoleDefine.GEDANG_RATE] = attr[RoleDefine.GEDANG_RATE]+bufAttr[RoleDefine.GEDANG_RATE]
end


function gedang(obj,buf,config,cmdConfig,rate,value,mianAttr,mainAttrRate)
	if not obj.attr[RoleDefine.GEDANG] then return end
	local bufAttr = obj.bufAttr
	bufAttr[RoleDefine.GEDANG] = bufAttr[RoleDefine.GEDANG] or 0
		
	local attr = 0
	if mianAttr and mianAttr~= 0 then
		attr = buf[mianAttr] * mainAttrRate	
	end
	
	value = attr + obj.attr[RoleDefine.GEDANG]*rate + value
	
	buf.gedang = value
	bufAttr[RoleDefine.GEDANG] = bufAttr[RoleDefine.GEDANG] +  value
end

function calcs.gedang(attr,bufAttr)
	if not attr[RoleDefine.GEDANG] or not bufAttr[RoleDefine.GEDANG] then return end
	attr[RoleDefine.GEDANG] = attr[RoleDefine.GEDANG]+bufAttr[RoleDefine.GEDANG]
end



function vampire(obj,buf,config,cmdConfig,rate,value)	 -- 吸血
	local bufAttr = obj.bufAttr
	bufAttr.vampireRate = bufAttr.vampireRate or 0
	bufAttr.vampire = bufAttr.vampire or 0
	
	bufAttr.vampire = bufAttr.vampire + value
	bufAttr.vampireRate = bufAttr.vampireRate + rate
end

function passive.vampire(obj,value) -- 吸血
	local bufAttr = obj.bufAttr
	if not bufAttr or not bufAttr.vampireRate then return end
	value = value*bufAttr.vampireRate
	value = value+bufAttr.vampire
	addHp(obj,value,obj.id)
end


function reflex(obj,buf,config,cmdConfig,rate)	--伤害反射
	local bufAttr = obj.bufAttr
	bufAttr.reflexRate = bufAttr.reflexRate or 0
	bufAttr.reflexRate = bufAttr.reflexRate + rate
end

function passive.reflex(send,recv,value)	--伤害反射
	local bufAttr = recv.bufAttr
	if not bufAttr.reflexRate or not send then return end
  send = Obj.getOwner(send) or send
	if send.obj_type ~= Obj.TYPE_HUMAN and send.obj_type ~= Obj.TYPE_MONSTER and send.obj_type ~= Obj.TYPE_PET then
	   return
	end
	value = value*bufAttr.reflexRate
	addHp(send,-value,recv.id)
end


function monsterReflex(obj,buf,config,cmdConfig,rate)	--伤害反射(怪物有效)
	local bufAttr = obj.bufAttr
	bufAttr.monsterReflexRate = bufAttr.monsterReflexRate or 0
	bufAttr.monsterReflexRate = bufAttr.monsterReflexRate + rate
end

function passive.monsterReflex(send,recv,value)	--伤害反射(怪物有效)
	if send.obj_type ~= Obj.TYPE_MONSTER then return end
	local bufAttr = recv.bufAttr
	if not bufAttr.monsterReflexRate then return end
	value = value*bufAttr.monsterReflexRate
	addHp(send,-value,recv.id)
end

function squelch(obj,buf)	
	local bufAttr = obj.bufAttr
	if not bufAttr.squelch then 
		bufAttr.squelch = buf
	end
end

function passive.squelch(send,recv)
	local bufAttr = recv.bufAttr	
	if not bufAttr.squelch then return end
	if not Conditions.canAttack(send) then return end
	if send.monster_id and send.can_hit==0 then return end
	
	local now = Timer.now
	if recv.squelchTime and now - recv.squelchTime <250 then	-- 250毫秒只能触发一次
		return
	end
	
	
	recv.squelchTime = now
	
	local buf = bufAttr.squelch
	local config = BufferExcel[buf.id]
	local cmdConfig = BufferCmdExcel[config.cmd]
	local rate,value,mainAttributes,mainAttributesAddition = Buffer.getAppendArg(buf,config,cmdConfig)

	local mustHit = true
	local isHit,isHeavyHit,isGedang,shanghai =  CombatCalc.hurt(recv,send,1,0,0,0,mainAttributes,mainAttributesAddition,mustHit)
	shanghai = shanghai*rate + value
	
	local mm = Msg.gc.GC_SKILL_TIP
	mm.type = 6	--反击
	mm.obj_id = recv.id
	Msg.send(mm,recv.fd)
	Msg.send(mm,send.fd)
	
	addHp(send,-shanghai ,recv.id)
end

function adds.avoidwar(obj)	-- 免战
	local bufAttr = obj.bufAttr
	bufAttr.avoidwar = true
end

function avoidwar(obj)	-- 免战
	local bufAttr = obj.bufAttr
	bufAttr.avoidwar = true
end

function passive.avoidwar(obj)	-- 免战
	return obj.bufAttr.avoidwar
end

function remove.avoidwar(obj)	-- 免战
	local bufAttr = obj.bufAttr
	bufAttr.avoidwar = false
	AvoidWar.sendAvoidAbout(obj, true)
	AvoidWar.sendQuery(obj, 1)
	RoleCombatMode.sendCombatMode(obj, true)		
end


function invincible(obj)	-- 无敌
	local bufAttr = obj.bufAttr
	bufAttr.invincible = true
end

function passive.invincible(obj)	-- 无敌
	return obj.bufAttr.invincible
end


function tempInvincible(obj)	--临时无敌
	local bufAttr = obj.bufAttr
	bufAttr.tempInvincible = true
end

function passive.tempInvincible(obj)--临时无敌
	return obj.bufAttr.tempInvincible
end

function adds.giddy(obj,buf,config,cmdConfig, type)
	local bufAttr = obj.bufAttr
	bufAttr.giddy = type
	Obj.stop(obj)
	obj.qianyao_begin_time = nil
	Buffer.delStop(obj,Buffer.STOP_TYPE_GIDDY)
end

-- 晕眩	0：正常晕眩，角色保持站立动作。
-- 1：角色动作保持在状态挂到身上时的那一帧
function giddy(obj,buf,config,cmdConfig,type)
	local bufAttr = obj.bufAttr
	bufAttr.giddy = type
end

function passive.giddy(obj)
	return obj.bufAttr.giddy
end

--落马
function adds.luoma(obj)
  if obj.obj_type ~= Obj.TYPE_HUMAN then
      return
  end
  obj.bufAttr.luoma = true
  Obj.stop(obj)
  obj.db.isMount = 0 
  HorseLogic.sendHorseStatus(obj)
  
  Notify.GC_SKILL_LIST(obj)
  Notify.GC_SKILL_LIST_CHANGE(obj)
  Notify.GC_SKILL_MAIN_MENU(obj)
end
function luoma(obj)
  if obj.obj_type ~= Obj.TYPE_HUMAN then
      return
  end
  obj.bufAttr.luoma = true
  obj.db.isMount = 0 
  HorseLogic.sendHorseStatus(obj)
end
function passive.luoma(obj)
  return obj.bufAttr.luoma
end

function adds.noMove(obj)	
	local bufAttr = obj.bufAttr
	bufAttr.noMove = true
	Obj.stop(obj)
end

function noMove(obj)	
	local bufAttr = obj.bufAttr
	bufAttr.noMove = true
end

function passive.noMove(obj)
	return obj.bufAttr.noMove
end

--沉默
function adds.noSkill(obj)	
	Buffer.delStop(obj,Buffer.STOP_TYPE_NO_SKILL)
end
function noSkill(obj)	
	local bufAttr = obj.bufAttr
	bufAttr.noSkill = true
end
function passive.noSkill(obj)
  return obj.bufAttr.noSkill
end
function baojiCallSkill(obj,buf)	
	local bufAttr = obj.bufAttr
	
	local baojiCallSkill = bufAttr.baojiCallSkill
	if not baojiCallSkill then
		obj.bufAttrBaojiCallSkill = obj.bufAttrBaojiCallSkill or {}
		baojiCallSkill = obj.bufAttrBaojiCallSkill
		for k in pairs(baojiCallSkill) do
			baojiCallSkill[k] = nil
		end
		bufAttr.baojiCallSkill = baojiCallSkill
	end
	
	baojiCallSkill[buf.id] = buf.skillLevel or 1
	
end

function passive.baojiCallSkill(obj)
	local bufAttr = obj.bufAttr
	if not bufAttr or not bufAttr.baojiCallSkill then return end
	if obj.baojiCallSkillTime and Timer.now - obj.baojiCallSkillTime <1000 then	-- 一秒只能触发一次
		return
	end
	local random = random(1,100)*0.01
	for id,skillLevel in pairs(bufAttr.baojiCallSkill) do
		local config	= BufferExcel[id]
		local rate		= config.arg[1]
		local skillID	= config.arg[2]
		if random<= rate then
			local x,y = obj.x, obj.y
			Skill.add(obj, skillID, x, y, x, y, nil, skillLevel)
			obj.baojiCallSkillTime = Timer.now
			break
		end
	end
end

function shanbiCallSkill(obj,buf)	
	
	local bufAttr = obj.bufAttr
	
	local shanbiCallSkill = bufAttr.shanbiCallSkill
	if not shanbiCallSkill then
		obj.bufAttrShanbiCallSkill = obj.bufAttrShanbiCallSkill or {}
		shanbiCallSkill = obj.bufAttrShanbiCallSkill
		for k in pairs(shanbiCallSkill) do
			shanbiCallSkill[k] = nil
		end
		bufAttr.shanbiCallSkill = shanbiCallSkill
	end
	
	shanbiCallSkill[buf.id] = buf.skillLevel or 1
	
end

function passive.shanbiCallSkill(obj)
	local bufAttr = obj.bufAttr
	if not bufAttr.shanbiCallSkill then return end
	
	local now = Timer.now
	if obj.shanbiCallSkillTime and now - obj.shanbiCallSkillTime <1000 then	-- 一秒只能触发一次
		return
	end
	
	local random = random(1,100)*0.01
	
	for id,skillLevel in pairs(bufAttr.shanbiCallSkill) do
		local config	= BufferExcel[id]
		local rate		= config.arg[1]
		local skillID	= config.arg[2]
		
		if random <= rate then
			local x, y = obj.x, obj.y
			Skill.add(obj, skillID, x, y, x, y, nil, skillLevel)
			obj.shanbiCallSkillTime = now
			break
		end
	end
end

function beHitCallSkill(obj,buf)	
	
	local bufAttr = obj.bufAttr
	
	local beHitCallSkill = bufAttr.beHitCallSkill
	if not beHitCallSkill then
		obj.bufAttrBeHitCallSkill = obj.bufAttrBeHitCallSkill or {}
		beHitCallSkill = obj.bufAttrBeHitCallSkill
		for k in pairs(beHitCallSkill) do
			beHitCallSkill[k] = nil
		end
		bufAttr.beHitCallSkill = beHitCallSkill
	end
	
	beHitCallSkill[buf.id] = buf.skillLevel or 1
	
end

function passive.beHitCallSkill(send, recv)
	local bufAttr = recv.bufAttr
	if not bufAttr.beHitCallSkill then return end
	
	for id,skillLevel in pairs(bufAttr.beHitCallSkill) do
		local random = random(1,100)*0.01
		local config	= BufferExcel[id]
		local rate		= config.arg[1]
		local skillID	= config.arg[2]
		
		if random<=rate  then
			Skill.add(recv, skillID, send.x, send.y, recv.x, recv.y, send, skillLevel)
			break
		end
	end
end

function hitCallSkill(obj,buf)	
	
	local bufAttr = obj.bufAttr
	
	local hitCallSkill = bufAttr.hitCallSkill
	if not hitCallSkill then
		obj.bufAttrHitCallSkill = obj.bufAttrHitCallSkill or {}
		hitCallSkill = obj.bufAttrHitCallSkill
		for k in pairs(hitCallSkill) do
			hitCallSkill[k] = nil
		end
		bufAttr.hitCallSkill = hitCallSkill
	end
	
	hitCallSkill[buf.id] = buf.skillLevel or 1
end

function passive.hitCallSkill(send,recv)
	local bufAttr = send.bufAttr
	if not bufAttr or not bufAttr.hitCallSkill then
		return 
	end
	local now = Timer.now
	
	local hitCallSkillTime = send.hitCallSkillTime
	if hitCallSkillTime and now - hitCallSkillTime <1000 then	-- 一秒只能触发一次
		return
	end
	
	local random = random(1,100)*0.01
	for id,skillLevel in pairs(bufAttr.hitCallSkill) do
		local config	= BufferExcel[id]
		local rate		= config.arg[1]
		local skillID	= config.arg[2]
		
		if random<=rate and SkillCoolDown.canUse(send, skillID) then
			
			Skill.add(send, skillID, recv.x, recv.y, send.x, send.y, recv, skillLevel)
			send.hitCallSkillTime = now
			break
		end
	end
end

function gedangCallSkill(obj,buf)	
	
	local bufAttr = obj.bufAttr
	
	local gedangCallSkill = bufAttr.gedangCallSkill
	if not gedangCallSkill then
		obj.bufAttrGedangCallSkill = obj.bufAttrGedangCallSkill or {}
		gedangCallSkill = obj.bufAttrGedangCallSkill
		for k in pairs(gedangCallSkill) do
			gedangCallSkill[k] = nil
		end
		bufAttr.gedangCallSkill = gedangCallSkill
	end
	
	gedangCallSkill[buf.id] = buf.skillLevel or 1
	
end

function passive.gedangCallSkill(obj, sender)
	local bufAttr = obj.bufAttr
	if not bufAttr.gedangCallSkill then return end
	
	local now = Timer.now
	if obj.gedangCallSkillTime and now - obj.gedangCallSkillTime <1000 then	-- 一秒只能触发一次
		return
	end
	
	local random = random(1,100)*0.01
	
	for id,skillLevel in pairs(bufAttr.gedangCallSkill) do
		local config	= BufferExcel[id]
		local rate		= config.arg[1]
		local skillID	= config.arg[2]
		
		if random <= rate then			
			Skill.add(obj, skillID, sender.x, sender.y, obj.x, obj.y, sender, skillLevel)
			obj.gedangCallSkillTime = now
			break
		end
	end
end



function adds.shanghaiOffset(obj, buf, config, cmdConfig, rate, value, attrType)
  local bufAttr = obj.bufAttr
	local hp = obj.attr[attrType]*rate + value
	buf.param = hp
	bufAttr.shanghaiOffset = true
end

function shanghaiOffset(obj)
  obj.bufAttr.shanghaiOffset = true
end

function passive.shanghaiOffset(send,obj,shangHai)
	local old = shangHai
	local bufList, len = Obj.getBuf(obj)
	for i=len-1,0,-1 do
		local buf = bufList[i]
		local config = BufferExcel[buf.id]
		if config.cmd =="shanghaiOffset" then			
			local shanghaiOffsetRate = config.arg[4]				
			local oldShanghaiOffset = buf.param
			buf.param = buf.param-shangHai*shanghaiOffsetRate			
			if buf.param >0 then
				shangHai = shangHai-shangHai*shanghaiOffsetRate
			else
				shangHai = shangHai-oldShanghaiOffset
				Buffer.remove(obj,buf)
			end
			shangHai = math.max(shangHai,0)
			if shangHai==0 then break end
		end
	end
	if old>shangHai then
		local mm = Msg.gc.GC_SKILL_TIP
		mm.type = 2
		mm.obj_id = obj.id
		Msg.send(mm,obj.fd)
		if send then
			Msg.send(mm,send.fd)
		end		
		BufferNotify.sendBufferList(obj,nil,true)	--更新伤害抵消BUFF
	end
	
	return shangHai
end


function skillMP(obj,buf,config,cmdConfig,rate,value)	
	local bufAttr = obj.bufAttr
	bufAttr.skillMPRate = bufAttr.skillMPRate or 0
	bufAttr.skillMPRate = bufAttr.skillMPRate+rate
	bufAttr.skillMPValue = bufAttr.skillMPValue or 0
	bufAttr.skillMPValue = bufAttr.skillMPValue+value
end

function passive.skillMP(obj,value)
	local bufAttr = obj.bufAttr
	if not bufAttr.skillMPRate then return value end
	return math.max(value*(1+bufAttr.skillMPRate)+bufAttr.skillMPValue,0)
end

-- [免疫状态作用]
function adds.immunityBuf(obj,buf,config,cmdConfig,cmd,isGood)
	Buffer.clearBuffUtility(obj,cmd,isGood,0xffffff)
end

function immunityBuf(obj)	
	
	local bufAttr = obj.bufAttr
	
	local immunityBuf = bufAttr.immunityBuf
	if not immunityBuf then
		obj.bufAttrImmunityBuf = obj.bufAttrImmunityBuf or {}
		immunityBuf = obj.bufAttrImmunityBuf
		for k in pairs(immunityBuf) do
			immunityBuf[k] = nil
		end
		bufAttr.immunityBuf = immunityBuf
	end
	
	
	immunityBuf[buf.id] = true
end

function passive.immunityBuf(obj,bufConfig,immunityCmd)
	local bufAttr = obj.bufAttr
	if not bufAttr.immunityBuf then return end
	
	for id in pairs(bufAttr.immunityBuf) do
		local config	= BufferExcel[id]
		local cmd		= config.arg[1]
		local isGood	= config.arg[2]
		
		if cmd==immunityCmd and isGood==bufConfig.isGood then return true end
	end
end

-- [免疫增益或减益buff]
function adds.immunityallBuf(obj,buf,config,cmdConfig,isGood)
  Buffer.clearBuf(obj,isGood,0xffffff)
  obj.bufAttr.immunityallBuf = isGood
end

function immunityallBuf(obj,buf,config,cmdConfig,isGood)   
  obj.bufAttr.immunityallBuf = isGood
end

function passive.immunityallBuf(obj,bufConfig)
  local bufAttr = obj.bufAttr
  if not bufAttr.immunityallBuf then return end
  return bufAttr.immunityallBuf==bufConfig.isGood
end

--免疫踢飞和换位
function adds.immunityMove(obj)
   obj.bufAttr.immunityMove = true
end

function immunityMove(obj)
   obj.bufAttr.immunityMove = true
end
function remove.immunityMove(obj)
   obj.bufAttr.immunityMove = nil
end
function passive.immunityMove(obj)
   return obj.bufAttr.immunityMove
end





-- [链接标记]
function linkFlag()	

end

-- [链接标记]
function loopCall.linkFlag(obj,buf,config,cmdConfig,type,tileID,maxLen,skillID)
	local send = Buffer.getSender(buf)
	
	if send and send.links then 
		if type==1 then --链人 并且链接标记中还有人
			local linkMain = Obj.getObj(send.linkMain,send.linkMainUid)
			if not linkMain or not send.links[send.linkMain] then
				if send.linkMain then 
					send.links[send.linkMain] = nil
				end
				local objID,uid = next(send.links)
				send.linkMain = objID
				send.linkMainUid = uid
			end
			if next(send.links) then
				if not linkMain and send.linkMain then
					BufferNotify.sendBufferList(send,nil,true)
				end
				if skillID and skillID~=0 then
					Skill.add(obj,skillID,obj.x,obj.y,obj.x, obj.y,obj,buf.skillLevel)
				end
				return
			end
		elseif type==2 and obj.scene_id == send.scene_id and  Util.dist(obj.x,obj.y,send.x,send.y)<=maxLen and send.links[obj.id]  then -- 被链
				if skillID and skillID~=0 then
					Skill.add(send,skillID,obj.x, obj.y,send.x,send.y,obj,buf.skillLevel)
				end
			return
		end	
	end
	Buffer.remove(obj,buf)
end


function setTypeArgs.linkFlag(obj,buf,typeArgs)
	local config = BufferExcel[buf.id]
	local send = Obj.objs[buf.sendID]
	local arg = config.arg
	if not send then
		typeArgs[0] = 0
		return
	end
	
	local isMoveStop = 0
	for _,v in ipairs(config.stop) do
		if v==Buffer.STOP_TYPE_MOVE then
			isMoveStop = 1
			break
		end
	end
	typeArgs[1] = arg[1]			--1：链人 2：被链
	typeArgs[2] = arg[2]			--平铺特效ID
	typeArgs[3] = isMoveStop		--移动阻断
	if arg[1]==2 then				--被链
		typeArgs[4] = buf.sendID
		typeArgs[5] = send.x
		typeArgs[6] = send.y
		typeArgs[0] = 6
	elseif arg[1]==1 then		--链人
		local len = 3
		if obj.links then
			for objID,uid in pairs(obj.links) do
				local target = Obj.getObj(objID,uid)
				if target then
					typeArgs[len+1] = objID
					typeArgs[len+2] = target.x	
					typeArgs[len+3] = target.y		
					len = len + 3	
				else
					obj.links[objID] = nil
				end
			end		
		end
		len = len+1
		typeArgs[len] = obj.linkMain or 0	--主光线
		typeArgs[0] = len 
	else
		assert()
	end

end

function remove.linkFlag(obj,buf)
	local send = Obj.objs[buf.sendID]
	if send and send.links then
		if send==obj then
			for k in pairs(send.links) do
				send.links[k] = nil
			end
		else
			send.links[obj.id] = nil			
		end
	end
end

function remove.link(obj,buf)
  local msg = Msg.gc.GC_BUFFER_LINK_CANEL
  msg.objid = obj.id
  Obj.sendArea(msg, obj.scene_id, obj.x, obj.y)
end

-- [技能改变]
function adds.skillChange(obj,buf)
	assert(obj.obj_type == Obj.TYPE_HUMAN)
	obj.bufAttr.skillChange = buf.id
	Notify.GC_SKILL_LIST_CHANGE(obj)
	Notify.GC_SKILL_MAIN_MENU(obj)
end

function skillChange(obj,buf)
	if obj.bufAttr.skillChange then return end
	obj.bufAttr.skillChange = buf.id
end



function passive.skillChange(obj,skillID)
	if not obj.bufAttr.skillChange then return true end
	if skillID==SkillDefine.SKILL_BACK_HOME_ID then return true	end-- 回城技能
	if skillID==SkillDefine.SKILL_ON_HORSE_ID then return true	end-- 坐骑技能
	local config = BufferExcel[obj.bufAttr.skillChange]
	for _,id in ipairs(config.arg) do
		if id==skillID or SkillExcel[id].group == SkillExcel[skillID].group then return true end
	end	
end

function other.skillChange(obj,mm)
	if not obj.bufAttr.skillChange then return end
	local config = BufferExcel[obj.bufAttr.skillChange]
	for i=1, 4 do
	  if i > #config.arg then
	     break
	  end
		mm.id[i] = config.arg[i]	  
	end
	mm.id[0] = #config.arg
	mm.horseSkill = config.arg[5] or 0
	mm.bowSkill = config.arg[6] or 0
	mm.qiliaoSkill = config.arg[7] or 0
	return true
end

function remove.skillChange(obj)
	assert(obj.obj_type == Obj.TYPE_HUMAN)
	obj.bufAttr.skillChange = nil
	Notify.GC_SKILL_LIST_CHANGE(obj)
	Notify.GC_SKILL_MAIN_MENU(obj)
end

-- [技能改变1]
function adds.oneSkillChange(obj,buf,config,cmdConfig,pos,skillID)
  if obj.bufAttr.skillChange then return end --只有神兵技能能改变其中一个技能 
  if obj.obj_type ~= Obj.TYPE_HUMAN then return end
  obj.bufAttr.oneSkillChange = buf.id
  Notify.GC_SKILL_CHANGE_ONE(obj, pos, skillID)
end

function oneSkillChange(obj,buf)
  if obj.bufAttr.skillChange then return end
  if obj.bufAttr.oneSkillChange then return end
  obj.bufAttr.oneSkillChange = buf.id
end
function other.oneSkillChange(obj,mm)
  if not obj.bufAttr.oneSkillChange then return end
  local config = BufferExcel[obj.bufAttr.oneSkillChange]
  if config.arg[1] <= mm.id[0] then
      mm.id[config.arg[1]] = config.arg[2]
  elseif config.arg[1] == 5 then
      mm.bowSkill = config.arg[2]
  elseif config.arg[1] == 6 then
      mm.horseSkill = config.arg[2]
  elseif config.arg[1] == 7 then
      mm.qiliaoSkill = config.arg[2]
  end
  return true
end

function remove.oneSkillChange(obj)
  if obj.obj_type ~= Obj.TYPE_HUMAN then return end
  obj.bufAttr.oneSkillChange = nil
  Notify.GC_SKILL_MAIN_MENU(obj)
end



-- 无双觉醒
function adds.awake(obj,buf)
  assert(obj.obj_type == Obj.TYPE_HUMAN)
  obj.bufAttr.awake = buf.id
  Notify.GC_SKILL_LIST_CHANGE(obj)
  Notify.GC_SKILL_MAIN_MENU(obj)
  local msg = Msg.gc.GC_AWAKE
  msg.objid = obj.id
  msg.status = 1
  msg.time   = buf.time
  Obj.sendArea(msg, obj.scene_id, obj.x, obj.y)
  Skill.add(obj, 1598, obj.x, obj.y, obj.x, obj.y,obj, 1, true)
end

function awake(obj,buf)
  if obj.bufAttr.awake then return end
  obj.bufAttr.awake = buf.id
end
function passive.awake(obj)
  return obj.bufAttr.awake
end
function other.awake(obj,mm)
  if not obj.bufAttr.awake then return end
  local config = BufferExcel[obj.bufAttr.awake]
  assert(#config.arg<7)
  for i=1, 4 do
    if i > #config.arg then
       break
    end
    mm.id[i] = config.arg[i]    
  end
  mm.id[0] = #config.arg
  mm.horseSkill = config.arg[5] or 0
  mm.bowSkill = config.arg[6] or 0
  return true
end
function remove.awake(obj)
  assert(obj.obj_type == Obj.TYPE_HUMAN)
  obj.bufAttr.awake = nil
  Notify.GC_SKILL_LIST_CHANGE(obj)
  Notify.GC_SKILL_MAIN_MENU(obj)
  Status.sendViewStatus(obj,true)  
  local msg = Msg.gc.GC_AWAKE
  msg.objid = obj.id
  msg.status = 0
  msg.time = 0
  Obj.sendArea(msg, obj.scene_id, obj.x, obj.y)
end

-- [移除制定CmdBuff作用]
function loopCall.clearBuffUtility(obj,buf,config,cmdConfig,cmd,isGood,num)
	Buffer.clearBuffUtility(obj,cmd,isGood,num)
end

-- [移除Buff作用]
function loopCall.clearBuf(obj,buf,config,cmdConfig,isGood,num)
	Buffer.clearBuf(obj,isGood,num)
end

-- [移除Buff组]
function loopCall.clearBuffGroup(obj,buf,config,cmdConfig,groupID)
	Buffer.clearBuffGroup(obj,groupID)
end

function shanghaiToAtk(obj,buf,config,cmdConfig,rate,atkRate,value)	
	if rate == 0 then
		return
	end
	local attr = obj.attr
	local bufAttr = obj.bufAttr
	local hp = Obj.getHpMax(obj) - Obj.getHp(obj)
	local hpBaseRate =  hp / Obj.getHpMax(obj)
	
	local num = hpBaseRate/rate + 1
	local atk = (num*atkRate)*attr[RoleDefine.ATK] + num*value
	buf.param = atk
	bufAttr[RoleDefine.ATK] = bufAttr[RoleDefine.ATK] or 0
	bufAttr[RoleDefine.ATK] = bufAttr[RoleDefine.ATK] + atk
end



function loopCall.shanghaiToAtk(obj)	
	Obj.doCalc(obj)
end

function calcs.shanghaiToAtk(attr,bufAttr)
	attr[RoleDefine.ATK] = attr[RoleDefine.ATK]+bufAttr[RoleDefine.ATK]
end

function loopCall.callSkill(obj,buf,config,cmdConfig,skillID)
  local skillConfig =SkillExcel[skillID]
  if Status.canSkill(obj, skillID,skillConfig) then
     if obj.obj_type == Obj.TYPE_HUMAN and obj.status == Status.HUMAN_STATUS_GUIDE then
       local tx,ty 
       if obj.skill_mouse_time and Timer.now - obj.skill_mouse_time < 5000 then
          tx,ty = Util.getAnglePoint2(obj.x, obj.y, obj.skill_mousex, obj.skill_mousey, 500)
       else
          tx,ty = Util.getAnglePoint(obj.dir or 2, obj.x, obj.y, 0,500)
       end
       local ret = Skill.add(obj, skillID,tx, ty, obj.x, obj.y, obj, buf.skillLevel, true)   
       if ret ~= true then --蓝不够，中断并提示
          buf.startTime = 0
          local mm   = Msg.gc.GC_SKILL_ERR
          mm.ret = ret
          Msg.send(mm, obj.fd)
       end    
     elseif obj.x then
         local tx,ty = Skill.fixDirAttackType(obj,skillID, skillConfig, obj.x, obj.y, buf.tx ~= 0 and buf.tx or obj.x, buf.ty~=0 and buf.ty or obj.y)
         Skill.add(obj, skillID,tx,ty, obj.x, obj.y, obj, buf.skillLevel)
	   end
	end
end

function loopCall.callSkillLv(obj,buf,config,cmdConfig,skillID, skillLv)
  local skillConfig =SkillExcel[skillID]
  if Status.canSkill(obj, skillID,skillConfig) then
     if obj.obj_type == Obj.TYPE_HUMAN and obj.status == Status.HUMAN_STATUS_GUIDE then
       local tx,ty 
       if obj.skill_mouse_time and Timer.now - obj.skill_mouse_time < 5000 then
          tx,ty = Util.getAnglePoint2(obj.x, obj.y, obj.skill_mousex, obj.skill_mousey, 500)
       else
          tx,ty = Util.getAnglePoint(obj.dir or 2, obj.x, obj.y, 0,500)
       end
       local ret = Skill.add(obj, skillID,tx, ty, obj.x, obj.y, obj, buf.skillLevel, true)   
       if ret ~= true then --蓝不够，中断并提示
          buf.startTime = 0
          local mm   = Msg.gc.GC_SKILL_ERR
          mm.ret = ret
          Msg.send(mm, obj.fd)
       end    
     elseif obj.x then
         local tx,ty = Skill.fixDirAttackType(obj,skillID, skillConfig, obj.x, obj.y, buf.tx ~= 0 and buf.tx or obj.x, buf.ty~=0 and buf.ty or obj.y)
         Skill.add(obj, skillID,tx,ty, obj.x, obj.y, obj, skillLv)
     end
  end
end
function loopCall.callAI(obj,buf,config,cmdConfig,aiID)
	if obj.obj_type == Obj.TYPE_MONSTER then
		obj.ref_ai_id = aiID	
	else
		--assert(nil,"loopCall.callAI is not monster")
	end
end

-- [技能改变]
function cooldownTime(obj,buf,config,cmdConfig,rate)
	local bufAttr = obj.bufAttr
	bufAttr.cooldownTime = bufAttr.cooldownTime or 0
	bufAttr.cooldownTime = bufAttr.cooldownTime + rate
end

function passive.cooldownTime(obj,coolDown)
	local bufAttr = obj.bufAttr
	if not bufAttr.cooldownTime then return coolDown end
	
	return math.max((1+bufAttr.cooldownTime)*coolDown,0)
end

function fear(obj,buf,config,cmdConfig)
	local bufAttr = obj.bufAttr
	bufAttr.giddy = 0
	noMove(obj,buf,config,cmdConfig)
	
	Buffer.delStop(obj,Buffer.STOP_TYPE_GIDDY)
end

function loopCall.fear(obj,buf,config,cmdConfig,radius)
	if obj.monster_id and ObjMonster.getValueByMonsterType(obj, "can_hit_back_fly") == 0 then
		return
	end
	
	local r = math.random()*radius
	local angle = math.random()*360
	local radian = angle/180*math.pi
	_G.map_mgr.monster_clear()
	SceneEvent.setBan(obj.scene_id)		
	Obj.move(obj,obj.x + r*math.cos(radian), obj.y + r*math.sin(radian), true)
	
	Status.onMove(obj)
end

function skillNoMP(obj,buf,config,cmdConfig,skillID)	
	local skillConfig = SkillExcel[skillID]
	if skillConfig.group and skillConfig.group~=0 then
		skillID = skillConfig.group
	end
	
	local bufAttr = obj.bufAttr
	local skillNoMP = bufAttr.skillNoMP
	
	if not skillNoMP then
		obj.bufAttrSkillNoMP = obj.bufAttrSkillNoMP or {}
		skillNoMP = obj.bufAttrSkillNoMP
		for k in pairs(skillNoMP) do
			skillNoMP[k] = nil
		end
		bufAttr.skillNoMP = skillNoMP
	end
	
	skillNoMP[skillID] = true
end

function passive.skillNoMP(obj,value,skillID)
	local bufAttr = obj.bufAttr
	
	local skillConfig = SkillExcel[skillID]
	if skillConfig and skillConfig.group~=0 then
		skillID = skillConfig.group
		if bufAttr.skillNoMP and bufAttr.skillNoMP[skillID] then 
			return 0 
		end
	end
	return value
end

function adds.copyAtk(obj,buf,config,cmdConfig,rate)
	buf.copyAtk = Obj.getAttr(Buffer.getSender(buf), RoleDefine.ATK)*rate
end

function copyAtk(obj,buf)	
	local bufAttr = obj.bufAttr
	bufAttr.copyAtk = bufAttr.copyAtk or 0
	bufAttr.copyAtk = bufAttr.copyAtk + buf.copyAtk
end

function calcs.copyAtk(attr,bufAttr)
	attr[RoleDefine.ATK] = attr[RoleDefine.ATK]+bufAttr.copyAtk
end

function adds.copyDef(obj,buf,config,cmdConfig,rate)
	buf.copyDef = Obj.getAttr(Buffer.getSender(buf), RoleDefine.DEF)*rate
end

function copyDef(obj,buf)
	local bufAttr = obj.bufAttr
	bufAttr.copyDef = bufAttr.copyDef or 0
	bufAttr.copyDef = bufAttr.copyDef + buf.copyDef
end

function calcs.copyDef(attr,bufAttr)
	attr[RoleDefine.DEF] = attr[RoleDefine.DEF]+bufAttr.copyDef
end



function adds.body(obj,buf)
	obj.bufAttr.body = buf.id
end

function body(obj,buf)
  obj.bufAttr.body = buf.id
end

function expRate(obj,buf,config,cmdConfig,rate)
	local bufAttr = obj.bufAttr
	bufAttr.expRate = bufAttr.expRate or 0
	bufAttr.expRate = bufAttr.expRate + rate
end

function passive.expRate(obj)
	local bufAttr = obj.bufAttr
	bufAttr.expRate = bufAttr.expRate or 0
	return bufAttr.expRate
end


function killCallSkill(obj,buf,config,cmdConfig,rate) --1:人物 2:怪物 3:怪物+人物
	local bufAttr = obj.bufAttr
	local killCallSkill = obj.killCallSkill or {}
	
	if not bufAttr.baojiCallSkill then
		for k in pairs(killCallSkill) do
			killCallSkill[k] = nil
		end
	end
	
	bufAttr.killCallSkill = killCallSkill
	killCallSkill[buf.id] = rate
end

function passive.killCallSkill(obj, target)
	if not obj then return end
	local bufAttr = obj.bufAttr
	if not bufAttr or not bufAttr.killCallSkill then return end
	if obj.killCallSkillTime and Timer.now - obj.killCallSkillTime <1000 then	-- 一秒只能触发一次
		return
	end
	obj.killCallSkillTime = Timer.now
	
	local targetType = target.obj_type
	local random = math.random(1,100)/100
	for id,rate in pairs(bufAttr.killCallSkill) do
		if random<= rate then
			local config = BufferExcel[id]
			local args = config.arg
			local skillID = args[2]
			local killType = args[3]
			if ((killType==1 or killType==3) and targetType==Obj.TYPE_HUMAN) or 
			   ((killType==2 or killType==3) and targetType==Obj.TYPE_MONSTER) then
				Skill.add(obj,skillID,obj.x,obj.y,0,obj.x,obj.y)
			end
			break
		end
	end
end


function huixinAtk(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.HUIXIN_RATE] = bufAttr[RoleDefine.HUIXIN_RATE] or 0
  bufAttr[RoleDefine.HUIXIN_RATE] = bufAttr[RoleDefine.HUIXIN_RATE] + value
end
function calcs.huixinAtk(attr,bufAttr)
  attr[RoleDefine.HUIXIN_RATE] = attr[RoleDefine.HUIXIN_RATE]+bufAttr[RoleDefine.HUIXIN_RATE]
end

function zhuoyueAtk(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.ZHUOYUE_RATE] = bufAttr[RoleDefine.ZHUOYUE_RATE] or 0
  bufAttr[RoleDefine.ZHUOYUE_RATE] = bufAttr[RoleDefine.ZHUOYUE_RATE] + value
end
function calcs.zhuoyueAtk(attr,bufAttr)
  attr[RoleDefine.ZHUOYUE_RATE] = attr[RoleDefine.ZHUOYUE_RATE]+bufAttr[RoleDefine.ZHUOYUE_RATE]
end

function doubleBaoji(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.MULTI_BAOJI_RATE] = bufAttr[RoleDefine.MULTI_BAOJI_RATE] or 0
  bufAttr[RoleDefine.MULTI_BAOJI_RATE] = bufAttr[RoleDefine.MULTI_BAOJI_RATE] + value
end
function calcs.doubleBaoji(attr,bufAttr)
  attr[RoleDefine.MULTI_BAOJI_RATE] = attr[RoleDefine.MULTI_BAOJI_RATE]+bufAttr[RoleDefine.MULTI_BAOJI_RATE]
end

function fengAtk(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.FENG_ATK] = bufAttr[RoleDefine.FENG_ATK] or 0
  bufAttr[RoleDefine.FENG_ATK] = bufAttr[RoleDefine.FENG_ATK] + value
end
function calcs.fengAtk(attr,bufAttr)
  attr[RoleDefine.FENG_ATK] = attr[RoleDefine.FENG_ATK]+bufAttr[RoleDefine.FENG_ATK]
end

function fengDef(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.FENG_KX] = bufAttr[RoleDefine.FENG_KX] or 0
  bufAttr[RoleDefine.FENG_KX] = bufAttr[RoleDefine.FENG_KX] + value
end
function calcs.fengDef(attr,bufAttr)
  attr[RoleDefine.FENG_KX] = attr[RoleDefine.FENG_KX]+bufAttr[RoleDefine.FENG_KX]
end

function fireAtk(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.FIRE_ATK] = bufAttr[RoleDefine.FIRE_ATK] or 0
  bufAttr[RoleDefine.FIRE_ATK] = bufAttr[RoleDefine.FIRE_ATK] + value
end
function calcs.fireAtk(attr,bufAttr)
  attr[RoleDefine.FIRE_ATK] = attr[RoleDefine.FIRE_ATK]+bufAttr[RoleDefine.FIRE_ATK]
end

function fireDef(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.FIRE_KX] = bufAttr[RoleDefine.FIRE_KX] or 0
  bufAttr[RoleDefine.FIRE_KX] = bufAttr[RoleDefine.FIRE_KX] + value
end
function calcs.fireDef(attr,bufAttr)
  attr[RoleDefine.FIRE_KX] = attr[RoleDefine.FIRE_KX]+bufAttr[RoleDefine.FIRE_KX]
end
function waterAtk(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.WATER_ATK] = bufAttr[RoleDefine.WATER_ATK] or 0
  bufAttr[RoleDefine.WATER_ATK] = bufAttr[RoleDefine.WATER_ATK] + value
end
function calcs.waterAtk(attr,bufAttr)
  attr[RoleDefine.WATER_ATK] = attr[RoleDefine.WATER_ATK]+bufAttr[RoleDefine.WATER_ATK]
end

function waterDef(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.WATER_KX] = bufAttr[RoleDefine.WATER_KX] or 0
  bufAttr[RoleDefine.WATER_KX] = bufAttr[RoleDefine.WATER_KX] + value
end
function calcs.waterDef(attr,bufAttr)
  attr[RoleDefine.WATER_KX] = attr[RoleDefine.WATER_KX]+bufAttr[RoleDefine.WATER_KX]
end

function leiAtk(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.LEI_ATK] = bufAttr[RoleDefine.LEI_ATK] or 0
  bufAttr[RoleDefine.LEI_ATK] = bufAttr[RoleDefine.LEI_ATK] + value
end
function calcs.leiAtk(attr,bufAttr)
  attr[RoleDefine.LEI_ATK] = attr[RoleDefine.LEI_ATK]+bufAttr[RoleDefine.LEI_ATK]
end

function leiDef(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.LEI_KX] = bufAttr[RoleDefine.LEI_KX] or 0
  bufAttr[RoleDefine.LEI_KX] = bufAttr[RoleDefine.LEI_KX] + value
end
function calcs.leiDef(attr,bufAttr)
  attr[RoleDefine.LEI_KX] = attr[RoleDefine.LEI_KX]+bufAttr[RoleDefine.LEI_KX]
end


function allAttrAtk(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.ALL_ATTR_ATK] = bufAttr[RoleDefine.ALL_ATTR_ATK] or 0
  bufAttr[RoleDefine.ALL_ATTR_ATK] = bufAttr[RoleDefine.ALL_ATTR_ATK] + value
  
end
function calcs.allAttrAtk(attr,bufAttr)
  attr[RoleDefine.FENG_ATK] = attr[RoleDefine.FENG_ATK]+bufAttr[RoleDefine.ALL_ATTR_ATK]
  attr[RoleDefine.FIRE_ATK] = attr[RoleDefine.FIRE_ATK]+bufAttr[RoleDefine.ALL_ATTR_ATK]
  attr[RoleDefine.WATER_ATK] = attr[RoleDefine.WATER_ATK]+bufAttr[RoleDefine.ALL_ATTR_ATK]
  attr[RoleDefine.LEI_ATK]  = attr[RoleDefine.LEI_ATK]+bufAttr[RoleDefine.ALL_ATTR_ATK]
end
function allAttrDef(obj,buf,config,cmdConfig,value)
  local bufAttr = obj.bufAttr
  bufAttr[RoleDefine.ALL_ATTR_KX] = bufAttr[RoleDefine.ALL_ATTR_KX] or 0
  bufAttr[RoleDefine.ALL_ATTR_KX] = bufAttr[RoleDefine.ALL_ATTR_KX] + value
end
function calcs.allAttrDef(attr,bufAttr)
  attr[RoleDefine.FENG_KX] = attr[RoleDefine.FENG_KX]+bufAttr[RoleDefine.ALL_ATTR_KX]
  attr[RoleDefine.FIRE_KX] = attr[RoleDefine.FIRE_KX]+bufAttr[RoleDefine.ALL_ATTR_KX]
  attr[RoleDefine.WATER_KX] = attr[RoleDefine.WATER_KX]+bufAttr[RoleDefine.ALL_ATTR_KX]
  attr[RoleDefine.LEI_KX] = attr[RoleDefine.LEI_KX]+bufAttr[RoleDefine.ALL_ATTR_KX]
end
-----------------------------------


for k in pairs(adds) do
	adds2key[#adds2key + 1] = k	
end

for k in pairs(loopCall) do
	loopCall2key[#loopCall2key + 1] = k	
end
